import sys
import cv2 as cv
import numpy as np
import math
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QPushButton, QFileDialog,
                             QTextEdit, QGroupBox, QFormLayout)
from PySide6.QtGui import QPixmap, QImage, QFont
from PySide6.QtCore import Qt
from img_processing import ImgProcessing


def is_square(points, tolerance=100):
    """检查四个点是否构成长方形（允许一定误差）"""
    if len(points) != 4:
        return False, "点的数量不是4个"

    # 计算所有点之间的距离
    points_np = np.array(points, dtype=np.float64)
    distances = []
    point_pairs = []  # 保存距离对应的点对，用于后续分析
    for i in range(4):
        for j in range(i + 1, 4):
            p1 = points_np[i]
            p2 = points_np[j]

            dist = np.linalg.norm(p1 - p2)
            distances.append(dist)
            point_pairs.append((i, j, dist))

    # 排序距离和对应的点对
    sorted_pairs = sorted(point_pairs, key=lambda x: x[2])
    distances.sort()

    # 长方形有4条边（2对相等的边）和2条对角线
    # 前4个为边，后2个为对角线
    sides = distances[:4]
    diagonals = distances[4:]

    # 检查边是否形成两对相等的边（长和宽）
    # 允许一定误差范围内的相等
    def are_equal(a, b, tol):
        return abs(a - b) <= tol

    # 检查边是否能组成两组对边
    if not (are_equal(sides[0], sides[1], tolerance) and are_equal(sides[2], sides[3], tolerance)) and \
            not (are_equal(sides[0], sides[2], tolerance) and are_equal(sides[1], sides[3], tolerance)) and \
            not (are_equal(sides[0], sides[3], tolerance) and are_equal(sides[1], sides[2], tolerance)):
        return False, f"边不能形成两组相等的对边，边长为: {[round(d, 2) for d in sides]}"

    # 检查两条对角线是否相等
    if len(diagonals) != 2:
        return False, "对角线数量不正确"

    if not are_equal(diagonals[0], diagonals[1], tolerance):
        return False, f"对角线长度不相等，差异: {abs(diagonals[0] - diagonals[1]):.2f}px"

    # 验证四个角是否为直角（通过向量点积判断垂直）
    # 先找到四个点的正确顺序（按顺时针或逆时针排列）
    # 计算各点的中心
    center = (sum(p[0] for p in points) / 4, sum(p[1] for p in points) / 4)

    # 计算各点相对于中心的角度，用于排序
    def get_angle(point):
        return math.atan2(point[1] - center[1], point[0] - center[0])

    # 按角度排序点，得到顺时针/逆时针顺序
    sorted_points = sorted(points, key=get_angle)

    # 计算相邻边的向量并检查是否垂直（点积接近0）
    for i in range(4):
        p1 = sorted_points[i]
        p2 = sorted_points[(i + 1) % 4]
        p3 = sorted_points[(i + 2) % 4]

        # 向量1: p2 - p1
        v1 = (p2[0] - p1[0], p2[1] - p1[1])
        # 向量2: p3 - p2
        v2 = (p3[0] - p2[0], p3[1] - p2[1])

        # 点积
        dot_product = v1[0] * v2[0] + v1[1] * v2[1]

        # 向量长度乘积
        len_v1 = math.hypot(v1[0], v1[1])
        len_v2 = math.hypot(v2[0], v2[1])

        if len_v1 == 0 or len_v2 == 0:
            return False, "存在重合的点"

        # 计算余弦值（接近0表示垂直）
        cos_theta = abs(dot_product) / (len_v1 * len_v2)

        # 允许一定误差（余弦值小于0.1视为接近直角）
        if cos_theta > 0.1:
            return False, f"角不是直角，余弦值: {cos_theta:.2f}"

    return True, "符合长方形特征"


class ImageProcessingUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 设置窗口标题和大小
        self.setWindowTitle('图像处理与长方形检查工具')
        self.setGeometry(100, 100, 1000, 80)

        # 创建中心部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # 按钮布局
        btn_layout = QHBoxLayout()
        self.load_btn = QPushButton('加载图片')
        self.process_btn = QPushButton('处理图片')
        self.check_btn = QPushButton('检查长方形')
        self.save_btn = QPushButton('保存结果')

        # 设置按钮样式
        button_style = """
            QPushButton {
                padding: 8px 15px;
                font-size: 14px;
                background-color: #f0f0f0;
                border: 1px solid #ccc;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #e0e0e0;
            }
            QPushButton:pressed {
                background-color: #d0d0d0;
            }
        """
        self.load_btn.setStyleSheet(button_style)
        self.process_btn.setStyleSheet(button_style)
        self.check_btn.setStyleSheet(button_style)
        self.save_btn.setStyleSheet(button_style)

        self.load_btn.clicked.connect(self.load_image)
        self.process_btn.clicked.connect(self.process_image)
        self.check_btn.clicked.connect(self.check_square)
        self.save_btn.clicked.connect(self.save_result)

        btn_layout.addWidget(self.load_btn)
        btn_layout.addWidget(self.process_btn)
        btn_layout.addWidget(self.check_btn)
        btn_layout.addWidget(self.save_btn)

        # 图片显示布局（左右分栏）
        img_layout = QHBoxLayout()

        # 左侧原图显示
        self.original_label = QLabel('原始图片')
        self.original_label.setAlignment(Qt.AlignCenter)
        self.original_label.setMinimumSize(400, 400)
        self.original_label.setStyleSheet("border: 1px solid #ccc; background-color: #f9f9f9;")

        # 右侧处理后图片显示
        self.processed_label = QLabel('处理后图片')
        self.processed_label.setAlignment(Qt.AlignCenter)
        self.processed_label.setMinimumSize(400, 400)
        self.processed_label.setStyleSheet("border: 1px solid #ccc; background-color: #f9f9f9;")

        img_layout.addWidget(self.original_label)
        img_layout.addWidget(self.processed_label)

        # 距离结果显示
        self.distance_label = QLabel('距离结果将显示在这里')
        self.distance_label.setAlignment(Qt.AlignCenter)
        self.distance_label.setStyleSheet("font-size: 14px; margin: 10px; padding: 5px; border: 1px solid #eee;")

        # 长方形检查结果显示（下部区域）
        result_group = QGroupBox("检查结果详情")
        result_group.setFont(QFont("Arial", 12, QFont.Bold))
        result_layout = QFormLayout()

        # 孔数量显示
        self.hole_count_label = QLabel("待检测")
        self.hole_count_label.setStyleSheet("font-size: 13px;")
        result_layout.addRow("孔数量:", self.hole_count_label)

        # 孔中心坐标显示
        self.hole_centers_label = QLabel("无数据")
        self.hole_centers_label.setStyleSheet("font-size: 13px;")
        self.hole_centers_label.setWordWrap(True)
        result_layout.addRow("孔中心坐标:", self.hole_centers_label)

        # 是否为长方形显示
        self.is_square_label = QLabel("待检测")
        self.is_square_label.setStyleSheet("font-size: 13px;")
        result_layout.addRow("是否为长方形:", self.is_square_label)

        # 检查消息显示
        self.message_label = QLabel("请先处理图片并检查")
        self.message_label.setStyleSheet("font-size: 13px; color: #666;")
        self.message_label.setWordWrap(True)
        result_layout.addRow("检查详情:", self.message_label)

        result_group.setLayout(result_layout)

        # 添加所有布局到主布局
        main_layout.addLayout(btn_layout)
        main_layout.addLayout(img_layout)
        main_layout.addWidget(self.distance_label)
        main_layout.addWidget(result_group)

        # 初始化变量
        self.original_img = None
        self.processed_img = None
        self.processing = None
        self.circle_points = None  # 用于存储检测到的圆的中心点

    def load_image(self):
        """加载原始图片"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图片", "", "图片文件 (*.png *.jpg *.jpeg *.bmp)"
        )
        if file_path:
            self.original_img = cv.imread(file_path)
            if self.original_img is not None:
                self.display_image(self.original_img, self.original_label)
                self.processed_label.setText('处理后图片')  # 重置右侧标签
                self.distance_label.setText('距离结果将显示在这里')  # 重置距离标签
                # 重置检查结果
                self.reset_check_results()
                self.circle_points = None

    def reset_check_results(self):
        """重置检查结果显示"""
        self.hole_count_label.setText("待检测")
        self.hole_centers_label.setText("无数据")
        self.is_square_label.setText("待检测")
        self.message_label.setText("请先处理图片并检查")

    def process_image(self):
        """处理图片并显示结果"""
        if self.original_img is None:
            self.distance_label.setText('请先加载图片')
            return

        try:
            # 创建处理实例
            self.processing = ImgProcessing(self.original_img)

            # 保存处理结果到临时文件
            temp_path = 'static/temp/temp_result.png'
            self.processing.img_show(temp_path)

            # 读取处理后的图片
            self.processed_img = cv.imread(temp_path)

            # 显示处理后的图片
            self.display_image(self.processed_img, self.processed_label)

            # 保存检测到的圆的中心点
            self.circle_points = self.processing.img_circle

            # 显示距离结果
            distances = self.processing.distance()
            self.distance_label.setText(
                f'距离结果: [{distances[0]:.2f}, {distances[1]:.2f}, {distances[2]:.2f}, {distances[3]:.2f}]'
            )

            # 更新孔数量显示
            self.hole_count_label.setText(str(len(self.circle_points)))

            # 更新孔中心坐标显示
            if len(self.circle_points) > 0:
                centers_text = "\n".join([f"点{i + 1}: ({int(x)}, {int(y)})"
                                          for i, (x, y) in enumerate(self.circle_points)])
                self.hole_centers_label.setText(centers_text)
            else:
                self.hole_centers_label.setText("未检测到孔")

        except Exception as e:
            self.distance_label.setText(f'处理出错: {str(e)}')
            self.reset_check_results()

    def check_square(self):
        """检查是否为长方形并显示结果"""
        if self.processing is None or self.circle_points is None:
            self.message_label.setText("请先处理图片")
            return

        # 调用is_square方法检查
        is_square_result, message = is_square(self.processing.img_circle) if len(self.processing.img_circle) == 4 else (
            False, "检测到的孔数量不是4个"
        )

        # 准备检查结果数据
        result_data = {
            'hole_count': len(self.processing.img_circle),
            'hole_centers': [{'x': int(x), 'y': int(y)} for (x, y) in self.processing.img_circle],
            'is_square': is_square_result,
            'message': message
        }

        # 更新UI显示
        self.hole_count_label.setText(str(result_data['hole_count']))

        # 更新孔中心坐标
        centers_text = "\n".join([f"点{i + 1}: ({data['x']}, {data['y']})"
                                  for i, data in enumerate(result_data['hole_centers'])])
        self.hole_centers_label.setText(centers_text)

        # 更新是否为长方形显示
        self.is_square_label.setText("是" if result_data['is_square'] else "否")
        # 根据结果设置不同颜色
        self.is_square_label.setStyleSheet(
            "font-size: 13px; color: green;" if result_data['is_square'] else
            "font-size: 13px; color: red;"
        )

        # 更新消息显示
        self.message_label.setText(result_data['message'])

    def save_result(self):
        """保存处理后的图片"""
        if self.processed_img is None:
            self.distance_label.setText('没有可保存的处理结果')
            return

        file_path, _ = QFileDialog.getSaveFileName(
            self, "保存结果", "", "PNG图片 (*.png);;JPEG图片 (*.jpg);;所有文件 (*)"
        )
        if file_path:
            cv.imwrite(file_path, self.processed_img)
            self.distance_label.setText(f'结果已保存到: {file_path}')

    def display_image(self, img, label):
        """在QLabel上显示OpenCV图像"""
        # 转换BGR为RGB
        rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

        # 获取图像尺寸
        h, w, c = rgb_img.shape

        # 计算缩放比例以适应标签大小
        scale = min(label.width() / w, label.height() / h, 1.0)
        new_w, new_h = int(w * scale), int(h * scale)
        resized_img = cv.resize(rgb_img, (new_w, new_h))

        # 转换为QImage
        qimg = QImage(
            resized_img.data, new_w, new_h, new_w * c,
            QImage.Format_RGB888
        )

        # 显示在标签上
        label.setPixmap(QPixmap.fromImage(qimg))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ImageProcessingUI()
    window.show()
    sys.exit(app.exec())
